package com.qcby.chatservice.socket.handle;


import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.qcby.chatservice.common.enums.GroupConst;
import com.qcby.chatservice.common.enums.SocketHandleType;
import com.qcby.chatservice.socket.context.FlowContext;
import com.qcby.chatservice.socket.service.IBaseChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.http.common.HttpRequest;
import org.tio.http.common.HttpResponse;
import org.tio.websocket.common.WsRequest;
import org.tio.websocket.common.WsResponse;
import org.tio.websocket.common.WsSessionContext;
import org.tio.websocket.server.handler.IWsMsgHandler;


import javax.annotation.Resource;
import java.util.Date;

/**
 * websocket处理程序
 *
 * @author cong.zhen
 * @date 2022/12/30
 */
@Slf4j
@Component
public class WsMsgHandler implements IWsMsgHandler {

    @Resource
    private IBaseChatService baseChatService;


    public static final WsMsgHandler me = new WsMsgHandler();
    private WsMsgHandler() {
    }



    /**
     * 握手
     *
     * @param httpRequest    http请求
     * @param httpResponse   http响应
     * @param channelContext 信道环境
     * @return {@link HttpResponse}
     * @throws Exception 异常
     */
    @Override
    public HttpResponse handshake(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {
        //获取到客户端的ip
        String clientIp = httpRequest.getClientIp();
        //此处姓名在header里获取
        String userId = httpRequest.getParam("userId");
        //将连接和用户绑定上，此处一般用用户id
        Tio.bindUser(channelContext, userId);
        log.info("收到来自{}的ws握手包\r\n{}", clientIp, httpRequest.toString());
        return httpResponse;
    }

    /**
     * 后握手
     *
     * @param httpRequest    http请求
     * @param httpResponse   http响应
     * @param channelContext 信道环境
     * @throws Exception 异常
     */
    @Override
    public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {
        //将用户链接绑定到群组，参数为群组id
        //todo 此处先写死群组id
        Tio.bindGroup(channelContext, GroupConst.GROUP_ID);
        int count = Tio.getAllChannelContexts(channelContext.tioConfig).getObj().size();
        String msg = "{name:'admin',message:'" + channelContext.userid + " 进来了，共【" + count + "】人在线" + "'}";
        //用tio-websocket，服务器发送到客户端的Packet都是WsResponse
        WsResponse wsResponse = WsResponse.fromText(msg, "utf-8");
        //群发
        Tio.sendToGroup(channelContext.tioConfig, GroupConst.GROUP_ID, wsResponse);
    }

    /**
     * binaryType = arraybuffer，时会走这个方法，二进制类型
     *
     * @param wsRequest      ws请求
     * @param bytes          字节
     * @param channelContext 信道环境
     * @return {@link Object}
     * @throws Exception 异常
     */
    @Override
    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
        return null;
    }

    /**
     * 连接关闭时调用此方法
     *
     * @param wsRequest      ws请求
     * @param bytes          字节
     * @param channelContext 信道环境
     * @return {@link Object}
     * @throws Exception 异常
     */
    @Override
    public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
        Tio.remove(channelContext, "关闭连接");
        return null;
    }

    /**
     * 字符消息（binaryType = blob）过来后会走这个方法
     *
     * @param wsRequest      ws请求
     * @param message         发送的消息
     * @param channelContext 信道环境
     * @return {@link Object}
     * @throws Exception 异常
     */
    @Override
    public Object onText(WsRequest wsRequest, String message, ChannelContext channelContext) throws Exception {
        //获取用户连接
        WsSessionContext wsSessionContext = (WsSessionContext) channelContext.getAttribute();
        //获取websocket握手包
        HttpRequest httpRequest = wsSessionContext.getHandshakeRequest();
        log.info("握手包:{}", httpRequest);
        log.info("收到ws消息:{}", message);

        //解析json
        FlowContext flowContext = JSONObject.parseObject(message, FlowContext.class);
        //用于保持socket连接不失活，一种续命机制
        if (StrUtil.equals(flowContext.getHandleType(), SocketHandleType.HEART.getCode())){
            log.info("收到客户端：{}，用户id:{}，的心跳",httpRequest.getClientIp(),channelContext.userid);
            return null;
        }
        //参数格式化
        paramFormat(flowContext,channelContext);
        baseChatService.doAction(flowContext);
        //todo 此处先直接拼写，后期要改成JsonUtil工具类
        String msg = "{name:'" + channelContext.userid + "',message:'" + message + "'}";
        //用tio-websocket，服务器发送到客户端的Packet都是WsResponse
        WsResponse wsResponse = WsResponse.fromText(msg, "utf-8");
        //群发
        Tio.sendToGroup(channelContext.tioConfig, GroupConst.GROUP_ID, wsResponse);
        //返回值是要发送给客户端的内容，这里先返回null，正常的应该是定义一个ack
        return null;
    }

    /**
     * 参数格式化
     *
     * @param flowContext    流上下文
     * @param channelContext 信道环境
     * @return {@link FlowContext}
     */
    private void paramFormat(FlowContext flowContext, ChannelContext channelContext){
        flowContext.setOperateEmp("11");
        flowContext.setOperateTime(new Date());
        flowContext.setChannelContext(channelContext);
    }
}
